#include "mainwindow.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSplitter>
#include <QFileDialog>
#include <QPixmap>
#include <QScrollArea>
#include <QDebug>
#include <QComboBox>
#include <QMessageBox>
#include <QPainter>
#include <QBuffer>
// 添加 OpenCV 到 QPixmap 的转换函数
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
// 添加网络请求
#include <curl/curl.h>// curl头文件
#include <QNetworkAccessManager>// 网络请求头文件
#include <QNetworkRequest>// 网络请求头文件
#include <QNetworkReply>// 网络请求头文件
#include <QJsonDocument>// json头文件
#include <QJsonObject>// json头文件
MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
{
    setWindowTitle("图像上传与文本设置界面");
    resize(1200, 800);
    // 创建一个新的 QWidget 作为左侧区域的容器
    QWidget *leftWidget = new QWidget;

    // 创建一个垂直布局管理器，负责控制左侧区域中控件的垂直排列
    QVBoxLayout *leftLayout = new QVBoxLayout(leftWidget);
    // 创建一个按钮，用于上传图像1
    QPushButton *btnLoad1 = new QPushButton("上传图像1");
    // 创建一个 QLabel 用于显示图像1，初始显示文字
    // imageLabel1 = new QLabel("图像1区域");
    imageLabel1 = new ImageLabel;

    // 设置图像显示居中对齐
    imageLabel1->setAlignment(Qt::AlignCenter);
    // 设置图像标签的尺寸策略为 Ignored，意味着它的尺寸可以被拉伸以适应父控件
    imageLabel1->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    // 设置图像标签内容可缩放以适应标签大小（开启缩放）
    // imageLabel1->setScaledContents(true); // <-- 问题所在：此行会破坏宽高比，干扰坐标计算，应移除
    // 为图像标签添加灰色边框，方便观察显示区域
    imageLabel1->setStyleSheet("border: 1px solid gray;");
    // 创建一个 QScrollArea 用于包装图像标签，实现滚动显示
    scrollArea1 = new QScrollArea;
    // 设置 QScrollArea 中显示的子控件为图像标签
    scrollArea1->setWidget(imageLabel1);
    // 启用自动调整 scrollArea 内容大小以适应图像变化
    scrollArea1->setWidgetResizable(true);

    // 将上传按钮添加到左侧布局中
    leftLayout->addWidget(btnLoad1);
    // 将图像显示区域（滚动区域）添加到左侧布局中
    leftLayout->addWidget(scrollArea1);


    // 中间图2上传
    QWidget *centerWidget = new QWidget;
    QVBoxLayout *centerLayout = new QVBoxLayout(centerWidget);
    QPushButton *btnLoad2 = new QPushButton("上传图像2");
    // imageLabel2 = new QLabel("图像2区域");
    imageLabel2 = new ImageLabel;
    imageLabel2->setAlignment(Qt::AlignCenter);
    imageLabel2->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    // imageLabel2->setScaledContents(true); // <-- 问题所在：此行会破坏宽高比，干扰坐标计算，应移除
    imageLabel2->setStyleSheet("border: 1px solid gray;");

    scrollArea2 = new QScrollArea;
    scrollArea2->setWidget(imageLabel2);
    scrollArea2->setWidgetResizable(true);
    centerLayout->addWidget(btnLoad2);
    centerLayout->addWidget(scrollArea2);


    // 右侧文本设置
    QWidget *rightWidget = new QWidget;
    QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget);
    // 设置一个按钮，清除标注
    QPushButton *clearButton = new QPushButton("清除标注");
    // 设计一个标注完成的按钮
    QPushButton *finishButton = new QPushButton("标注完成");
    // 设计一个按钮返回原图
    QPushButton *returnButton = new QPushButton("返回原图");
    // 设置一个OCR识别的按钮
    QPushButton *ocrButton = new QPushButton("OCR识别");
    // 设置一个下拉框分别为语言选择，设置中文、英文、日文、韩文、德文、法文几个选项。默认是中文
    languageComboBox = new QComboBox;
    languageComboBox->addItem("中文");
    languageComboBox->addItem("英文");
    languageComboBox->addItem("日文");
    languageComboBox->addItem("韩文");
    languageComboBox->addItem("德文");
    languageComboBox->addItem("法文");
    languageComboBox->setCurrentIndex(0);

    rightLayout->addWidget(clearButton);
    rightLayout->addWidget(finishButton);
    rightLayout->addWidget(returnButton);
    rightLayout->addWidget(ocrButton);
    rightLayout->addWidget(languageComboBox);

    QLabel *label = new QLabel("文本设置：");
    textEditor = new QTextEdit;
    textEditor->setPlaceholderText("在此输入设置内容...");
    textEditor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    rightLayout->addWidget(label);
    rightLayout->addWidget(textEditor);

    // 使用 QSplitter 实现三栏布局，支持自动拉伸
    QSplitter *mainSplitter = new QSplitter(Qt::Horizontal);
    mainSplitter->addWidget(leftWidget);
    mainSplitter->addWidget(centerWidget);
    mainSplitter->addWidget(rightWidget);

    mainSplitter->setStretchFactor(0, 9);  // 左边 stretch 4
    mainSplitter->setStretchFactor(1, 9);  // 中间 stretch 4
    mainSplitter->setStretchFactor(2, 2);  // 右边 stretch 2

    setCentralWidget(mainSplitter);

    // 连接上传按钮的点击信号到对应的槽函数 loadImage1，用于选择图像
    connect(btnLoad1, &QPushButton::clicked, this, &MainWindow::loadImage1);
    // 按钮2和相关函数进行连接
    connect(btnLoad2, &QPushButton::clicked, this, &MainWindow::loadImage2);
    // 连接清除按钮
    connect(clearButton, &QPushButton::clicked, this, &MainWindow::clearButtonfunction);
    // 添加OCR识别功能
    connect(ocrButton, &QPushButton::clicked, this, &MainWindow::OCRDealFunction);
    // 添加标注完成按钮
    connect(finishButton, &QPushButton::clicked, this, &MainWindow::finishButtonFunction);
    // 返回原图操作
    connect(returnButton, &QPushButton::clicked, this, &MainWindow::returnButtonFunction);
}
MainWindow::~MainWindow() {}


void MainWindow::loadImage1() {
    // 打开文件选择对话框，让用户选择图像1文件（支持 png, jpg, jpeg 格式）
    QString fileName = QFileDialog::getOpenFileName(
            this,                    // 父窗口指针
            "选择图像1",             // 对话框标题
            "",                      // 默认打开路径（空表示使用默认）
            "Images (*.png *.jpg *.jpeg)" // 文件过滤器：只显示常见图像类型
    );
    // 如果用户选择了图像（文件路径不为空）
    if (!fileName.isEmpty()) {
        // 使用选中的文件路径创建 QPixmap 对象并保存到成员变量 originalPixmap1 中
        originalPixmap1 = QPixmap(fileName);
        // 将图像传递给 ImageLabel 控件中的自定义函数 setOriginalPixmap，用于缩放显示和标注
        imageLabel1->setOriginalPixmap(originalPixmap1);
    }
}

void MainWindow::loadImage2() {
    // 打开文件选择对话框，让用户选择图像1文件（支持 png, jpg, jpeg 格式）
    QString fileName = QFileDialog::getOpenFileName(
            this,                    // 父窗口指针
            "选择图像2",             // 对话框标题
            "",                      // 默认打开路径（空表示使用默认）
            "Images (*.png *.jpg *.jpeg)" // 文件过滤器：只显示常见图像类型
    );
    // 如果用户选择了图像（文件路径不为空）
    if (!fileName.isEmpty()) {
        // 使用选中的文件路径创建 QPixmap 对象并保存到成员变量 originalPixmap2 中
        originalPixmap2 = QPixmap(fileName);
        imageLabel2->setOriginalPixmap(originalPixmap2);
    }
}

// 对点的信息进行清除
void MainWindow::clearButtonfunction() {
    imageLabel1->clearPoints();
    imageLabel2->clearPoints();
}


// QPixmap 转换为 cv::Mat（用于 OpenCV 图像处理）
// 输入: QPixmap 类型的图像（Qt 显示用）
// 输出: cv::Mat 类型的图像（OpenCV 处理用）
static cv::Mat QPixmapToCvMat(const QPixmap &inPixmap) {
    // 将 QPixmap 转换为 QImage，并统一格式为 RGB888（每像素3通道，R、G、B）
    QImage srcImage = inPixmap.toImage().convertToFormat(QImage::Format_RGB888);
    // 用 QImage 的数据指针创建一个 cv::Mat 对象
    // 参数依次为：图像高度、宽度、数据类型、数据指针、每行步长（字节数）
    cv::Mat mat(srcImage.height(),                 // 高度
                srcImage.width(),                  // 宽度
                CV_8UC3,                           // 数据类型：8位无符号整数，3通道
                (void*)srcImage.constBits(),       // 图像数据指针（const 转 void*）
                srcImage.bytesPerLine());          // 每行像素占用的字节数
    // 返回数据的副本（clone），防止原始 QImage 数据释放后造成野指针问题
    return mat.clone();
}
// 将 OpenCV 的 cv::Mat 图像转换为 Qt 的 QPixmap 图像
// 输入: OpenCV 的 cv::Mat 图像（BGR 或灰度图）
// 输出: Qt 的 QPixmap 图像（可直接用于 QLabel、QPainter 等）
static QPixmap cvMatToQPixmap(const cv::Mat &inMat) {
    // 判断输入图像是否为 8位3通道彩色图像（BGR 格式）
    if (inMat.type() == CV_8UC3) {
        // 构造 QImage 对象，使用 QImage::Format_RGB888 格式
        // 注意：OpenCV 使用 BGR 顺序，而 QImage 使用 RGB，所以稍后需要通道交换
        QImage image(inMat.data,               // 数据指针（Mat 的像素数据）
                     inMat.cols,               // 图像宽度
                     inMat.rows,               // 图像高度
                     static_cast<int>(inMat.step), // 每行字节数（步长）
                     QImage::Format_BGR888);   // 图像格式（RGB，每像素3字节）
        // 通道交换：将 BGR 转换为 RGB，并生成 QPixmap 返回
        return QPixmap::fromImage(image.rgbSwapped());
    }
    // 否则，处理为灰度图（单通道图像）
    // CV_8UC1 -> QImage::Format_Grayscale8 是一一对应的格式
    return QPixmap::fromImage(QImage(inMat.data,
                                     inMat.cols,
                                     inMat.rows,
                                     static_cast<int>(inMat.step),
                                     QImage::Format_Grayscale8));
}
QPixmap cropAndPreprocess(const QPixmap& sourcePixmap, const std::vector<QPoint>& points) {
    if (points.size() < 3) {
        qWarning() << "Processing requires at least 3 points.";
        return {};
    }
    // QPixmap 转 cv::Mat
    cv::Mat sourceMat = QPixmapToCvMat(sourcePixmap);
    // 转换 QPoint 到 cv::Point2f
    std::vector<cv::Point2f> cvPoints;
    for (const auto& p : points) {
        cvPoints.emplace_back(p.x(), p.y());
    }
    // 1. 最小外接旋转矩形
    cv::RotatedRect minAreaRect = cv::minAreaRect(cvPoints);
    cv::Point2f rectPoints[4];
    minAreaRect.points(rectPoints);
    // 2. 排序角点为 tl, tr, br, bl（按 y 轴排，之后按 x 排）
    std::sort(rectPoints, rectPoints + 4, [](const cv::Point2f& a, const cv::Point2f& b) {
        return a.y < b.y;
    });
    if (rectPoints[0].x > rectPoints[1].x) std::swap(rectPoints[0], rectPoints[1]);
    if (rectPoints[2].x < rectPoints[3].x) std::swap(rectPoints[2], rectPoints[3]);
    // 源图像中提取的 4 个角点（按顺时针：tl, tr, bl, br）
    std::vector<cv::Point2f> srcPoints = {rectPoints[0], rectPoints[1], rectPoints[3], rectPoints[2]};
    // 计算目标图像的宽高
    float width = cv::norm(srcPoints[1] - srcPoints[0]);
    float height = cv::norm(srcPoints[2] - srcPoints[0]);
    // 定义目标图像的四个角点
    std::vector<cv::Point2f> dstPoints = {
            {0, 0},
            {width - 1, 0},
            {0, height - 1},
            {width - 1, height - 1}
    };
    // 3. 执行透视变换
    cv::Mat transformMatrix = cv::getPerspectiveTransform(srcPoints, dstPoints);
    cv::Mat warpedMat;
    cv::warpPerspective(sourceMat, warpedMat, transformMatrix, cv::Size(width, height));
    // ✅ 返回矫正后的原图 QPixmap
    return cvMatToQPixmap(warpedMat);
}

// OCR识别功能 (此函数将被移除或合并)
void MainWindow::OCRDealFunction() {
    qDebug() << "OCRDealFunction() called."<<endl;
    // 获得图1的图片
    QPixmap image1 = processedPixmap1;
    QPixmap image2 = processedPixmap2;
    // 2. 将图像1转换为Base64
    QByteArray byteArray1;
    QBuffer buffer1(&byteArray1);
    buffer1.open(QIODevice::WriteOnly); // 打开buffer用于写入
    image1.save(&buffer1, "PNG");       // 将image1以PNG格式写入buffer
    QByteArray image1_base64 = byteArray1.toBase64(); // 转换
    // 3. 将图像2转换为Base64
    QByteArray byteArray2;
    QBuffer buffer2(&byteArray2);
    buffer2.open(QIODevice::WriteOnly);
    image2.save(&buffer2, "PNG");
    QByteArray image2_base64 = byteArray2.toBase64();
    // 创建网络访问管理器
    QNetworkAccessManager* manager = new QNetworkAccessManager(this);
    // 请求地址
    QUrl url("http://127.0.0.1:8080/testapi/PPOCRv5/ocrv5detectmatch");  // 本结构将同时实现点匹配,ocr和色差检测
    QNetworkRequest request(url);
    // 设置请求头
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject JSONObject;// 整体 JSON 构造
    JSONObject["base64_1"] =  QString::fromUtf8(image1_base64);
    JSONObject["base64_2"] =  QString::fromUtf8(image2_base64);
    QJsonObject configObj;// 创建 JSON 数据
    QString lang = getCurrentLanguage();// 获得当前的语言

    configObj["lang"] =lang;
    JSONObject["config"] = configObj;
    QJsonDocument jsonDoc(JSONObject);// 创建JSON文档
    QByteArray jsonData = jsonDoc.toJson();// 转换为字节数组
    // 发送POST请求
    QNetworkReply* reply = manager->post(request, jsonData);
    // 处理响应
    connect(reply, &QNetworkReply::finished, [=]() {
        if (reply->error() == QNetworkReply::NoError) {
            // 开始处理响应
            QByteArray responseData = reply->readAll();// 获取响应数据
            QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);// 解析JSON数据
            QJsonObject jsonObject = jsonResponse.object();// 获取JSON对象
            // 起码处理是完成的
            // qDebug() << "Response: " << jsonObject << endl;
            QString status = jsonObject["status"].toString();// 获取状态
            int code = jsonObject["code"].toInt();
            if (code == 200) {
                QString image1_result_txt = jsonObject["image1_result_txt"].toString();
                QString image2_result_txt = jsonObject["image2_result_txt"].toString();
                double similarity = jsonObject["similarity"].toDouble();
                // 转化成字符串的形式
                QString similarityString = QString::number(similarity, 'f', 2);
                QString resultMessage = "";
                if (image1_result_txt == image2_result_txt){
                    resultMessage = "图片1和图片2的文字内容相同。";
                }else{
                    resultMessage = "图片1和图片2的文字内容不同。";
                }
                // 在文本的区域显示结果结果
                QString showResult = "text1:"+image1_result_txt+"\ntext2:"+image2_result_txt+
                        "\nresultMessage:"+resultMessage+"\nsimilarity:"+similarityString;
                textEditor->setPlainText(showResult);
            }else if (code == 400) {
                QMessageBox::warning(this, "错误", "请检查输入的图片是否正确。");
            } else {
                QMessageBox::warning(this, "错误", "未知错误。");
            }
        }
    });
}
// 实现对标注完成的按钮操作
void MainWindow::finishButtonFunction() {
    // --- 处理图像1 ---
    if (!originalPixmap1.isNull()) {
        const auto& points1_std = imageLabel1->getPoints();
        if (!points1_std.empty()) { // 只要有标注点就处理
            processedPixmap1 = cropAndPreprocess(originalPixmap1, points1_std);
            if (!processedPixmap1.isNull()) {
                //放置到图1的位置
                imageLabel1->setOriginalPixmap(processedPixmap1);
            } else {
                QMessageBox::warning(this, "处理失败", "无法处理图像1，请确保标注了至少3个点。");
            }
        }
    }
    // --- 处理图像2 (类似逻辑) ---
    if (!originalPixmap2.isNull()) {
        const auto& points2_std = imageLabel2->getPoints();
        if (!points2_std.empty()) {
            processedPixmap2 = cropAndPreprocess(originalPixmap2, points2_std);
            if (!processedPixmap2.isNull()) {
                // 放置到图2的位置
                imageLabel2->setOriginalPixmap(processedPixmap2);
            }else {
                QMessageBox::warning(this, "处理失败", "无法处理图像1，请确保标注了至少3个点。");
            }
        }
    }
    // 清除标注点以便进行下一次标注
    imageLabel1->clearPoints();
    imageLabel2->clearPoints();
}

void MainWindow::returnButtonFunction() {
    // 图1 图2 设计原图的操作
    imageLabel1->setOriginalPixmap(originalPixmap1);
    imageLabel2->setOriginalPixmap(originalPixmap2);
}

QString MainWindow::getCurrentLanguage() {
    return languageComboBox->currentText();
}
// 调整尺寸大小
void MainWindow::resizeEvent(QResizeEvent* event) {
    QMainWindow::resizeEvent(event); // 调用基类实现，并移到最前
    if (!originalPixmap1.isNull()) {
        imageLabel1->setOriginalPixmap(originalPixmap1); // 让 ImageLabel 重新缩放
    }
    if (!originalPixmap2.isNull()) {
        imageLabel2->setOriginalPixmap(originalPixmap2);
    }
}